module source.oparse;

import std.json : parseJSON, JSONValue;
import std.algorithm : remove, canFind;
import std.file : exists, isFile;

import source.config : ConfigManager;
import source.logger : LoggerWriter;
import source.modules : ModuleManager;
import source.irc : Irc;

class OutputParser
{
    private ConfigManager manager;
    private LoggerWriter logger;
    private ModuleManager functManager;
    private Irc connection;

    this(ConfigManager manager, LoggerWriter logger, ModuleManager functManager, Irc conn)
    {
        this.manager = manager;
        this.logger = logger;
        this.functManager = functManager;
        this.connection = conn;
    }

    public int parseOutput(string output)
    {
        JSONValue outputJ = parseJSON(output);
        switch (outputJ["method"].str)
        {
            case "irc":
                return this.parseIrc(outputJ["submethod"].str, outputJ["data"].str);

            case "core":
                return this.parseCore(outputJ["submethod"].str, outputJ["data"].str);

            default:
                return 0;
        }
    }

    private int parseIrc(string subMethod, string data)
    {
        switch (subMethod)
        {
            case "send":
                this.connection.send(data);
                return 0;

            case "join":
                JSONValue chann = parseJSON(data);
                this.connection.joinChannel(chann["chan"].str, chann["key"].str);
                this.manager.chankeys[chann["chan"].str] = chann["key"].str;
                this.manager.saveAssets();
                this.manager.reloadAssets();
                return 0;

            case "part":
                JSONValue chann = parseJSON(data);
                if (this.connection.partChannel(chann["chan"].str) == 1)
                {
                    this.manager.chankeys.remove(chann["chan"].str);
                    this.manager.saveAssets();
                    this.manager.reloadAssets();
                }
                return 0;

            default:
                return 0;
        }
    }

    private int parseCore(string subMethod, string data)
    {
        switch (subMethod)
        {
            case "exit":
                return 1;

            case "addmodule":
                if (this.manager.available.canFind(data) == false && exists(this.manager.modulepath~"/"~data) && isFile(this.manager.modulepath~"/"~data))
                {
                    this.manager.available ~= data;
                    this.manager.saveAssets();
                    this.manager.reloadAssets();
                    this.functManager.reloadModules();
                }
                return 0;

            case "delmodule":
                if (this.manager.available.canFind(data))
                {
                    for (int i = 0; i < this.manager.available.length; i++)
                    {
                        if (this.manager.available[i] == data)
                        {
                            this.manager.available = this.manager.available.remove(i);
                            this.manager.saveAssets();
                            this.manager.reloadAssets();
                            this.functManager.reloadModules();
                            return 0;
                        }
                    }
                }
                return 0;

            case "addignored":
                if (this.manager.ignored.canFind(data) == false)
                {
                    this.manager.ignored ~= data;
                    this.manager.saveAssets();
                    this.manager.reloadAssets();
                }
                return 0;

            case "delignored":
                if (this.manager.ignored.canFind(data))
                {
                    for (int i = 0; i < this.manager.ignored.length; i++)
                    {
                        if (this.manager.ignored[i] == data)
                        {
                            this.manager.ignored = this.manager.ignored.remove(i);
                            this.manager.saveAssets();
                            this.manager.reloadAssets();
                            return 0;
                        }
                    }
                }
                return 0;

            case "addkey":
                JSONValue apikey = parseJSON(data);
                this.manager.apiKeys[apikey["name"].str] = apikey["key"].str;
                this.manager.saveAssets();
                this.manager.reloadAssets();
                return 0;

            case "delkey":
                if ((data in this.manager.apiKeys) != null)
                {
                    foreach (string keyname, string keyvalue; this.manager.apiKeys)
                    {
                        if (keyname == data)
                        {
                            this.manager.apiKeys.remove(data);
                            this.manager.saveAssets();
                            this.manager.reloadAssets();
                            return 0;
                        }
                    }
                }
                return 0;

            case "addacc":
                JSONValue access = parseJSON(data);
                this.manager.accessibility[access["user"].str] = cast(int)access["acc"].integer;
                this.manager.saveAssets();
                this.manager.reloadAssets();
                return 0;

            case "delacc":
                if ((data in this.manager.accessibility) != null)
                {
                    foreach (string username, int accesslevel; this.manager.accessibility)
                    {
                        if (username == data)
                        {
                            this.manager.accessibility.remove(data);
                            this.manager.saveAssets();
                            this.manager.reloadAssets();
                            return 0;
                        }
                    }
                }
                return 0;

            case "listmodules":
                string output = "PRIVMSG " ~ data ~ " :";
                for (int i = 0; i < this.manager.available.length; i++)
                {
                    output ~= this.manager.available[i] ~ ", ";
                }
                output.length -= 2;
                this.connection.send(output);
                return 0;

            default:
                return 0;
        }
    }
}
